#!/opt/sysroot64/usr/bin/python3.9
# -*- coding: utf-8 -*-
# @Time    : 2025/02/17 11:57
# @Author  : fy
# @File    : main.py
# @Software: PyCharm
import os
import sys
import yaml
import getpass
import argparse
from util.base import CheckIP, CheckPort, path_type, positive_int_type, write_to_terminal, set_logger
from util.base import is_exporter_alive
from test import service
from test import uvicorn_main

ROOT_DIR_PATH = os.path.realpath(
    os.path.join(os.path.dirname(__file__))
)

DEFAULT_YAML = 'default.yml'
DEFAULT_LOGFILE = 'myexporter.log'


def parse_and_adjust_args(parser, argv):
    args = parser.parse_args(argv)

    ssl_keyfile_pwd = None
    if args.disable_https:
        # Clear up redundant arguments.
        args.ssl_keyfile = None
        args.ssl_certfile = None
    else:
        if not (args.ssl_keyfile and args.ssl_certfile):
            parser.error('If you use the Https protocol (default), you need to give the argument values '
                         'of --ssl-keyfile and --ssl-certfile. '
                         'Otherwise, use the --disable-https argument to disable the Https protocol.')
        else:
            # Need to check whether the key file has been encrypted.
            with open(args.ssl_keyfile) as fp:
                for line in fp.readlines():
                    if line.startswith('Proc-Type') and 'ENCRYPTED' in line.upper():
                        ssl_keyfile_pwd = ''
                        while not ssl_keyfile_pwd:
                            ssl_keyfile_pwd = getpass.getpass('Enter PEM pass phrase:')
    setattr(args, 'keyfile_password', ssl_keyfile_pwd)
    return args

def parse_argv(argv):
    parser = argparse.ArgumentParser(
        description='MyExporter'
    )

    parser.add_argument('--url', default=None, help='target url to connect')

    parser.add_argument('--pg_conn', default="postgresql://psql:psql@127.0.0.1:5236/postgres",
                        help='postgresql url to connect')

    parser.add_argument('--config-file', '--config', type=path_type, default=os.path.join(ROOT_DIR_PATH, DEFAULT_YAML),
                        help='path to config file.')

    parser.add_argument('--web.listen-address', default='0.0.0.0', action=CheckIP,
                        help='address on which to expose metrics and web interface')

    parser.add_argument('--web.listen-port', type=int, default=4030, action=CheckPort,
                        help='listen port to expose metrics and web interface')

    parser.add_argument('--log.filepath', type=os.path.realpath,
                        default=os.path.join(os.getcwd(), DEFAULT_LOGFILE),
                        help='the path to log')
    parser.add_argument('--log.level', default='debug', choices=('debug', 'info', 'warn', 'error', 'fatal'),
                        help='only log messages with the given severity or above.'
                             ' Valid levels: [debug, info, warn, error, fatal]')

    parser.add_argument('--disable-https', action='store_true', default=True,
                        help='disable Https scheme')

    parser.add_argument('--disable-cache', action='store_true',
                        help='force not using cache.')

    parser.add_argument('--ssl-keyfile', type=path_type, help='set the path of ssl key file')
    parser.add_argument('--ssl-certfile', type=path_type, help='set the path of ssl certificate file')
    parser.add_argument('--ssl-ca-file', type=path_type, help='set the path of ssl ca file')
    parser.add_argument('--parallel', default=5, type=positive_int_type,
                        help='number of parallels for metrics scrape.')

    args = parse_and_adjust_args(parser, argv)
    return args

class ExporterMain(object):
    def clean(self):
        pass

    def __init__(self, args):
        self.args = args

    def run(self):

        set_logger(self.args.__dict__['log.filepath'],
                   self.args.__dict__['log.level'])
        url = self.args.url  # to label instance
        if url is None:
            print("testonly...")
            url = "{}:{}".format(self.args.__dict__['web.listen_address'], self.args.__dict__['web.listen_port'])
        url_dict = {'url': url, "pg_conn": self.args.pg_conn}
        try:
            service.config_collecting_params(
                url_dict=url_dict,
                parallel=self.args.parallel,
                disable_cache=self.args.disable_cache,
            )
        except ConnectionError:
            write_to_terminal('Failed to connect to the url, exiting...', color='red')
            sys.exit(1)
        except Exception as e:
            write_to_terminal('Failed to connect to the url due to exception, exiting...', color='red')
            raise e

        # register metrics from yaml
        with open(self.args.config_file, errors='ignore') as fp:
            service.register_metrics(
                yaml.load(fp, Loader=yaml.FullLoader),
                url_dict
            )

        # ssl
        # warn_ssl_certificate(self.args.ssl_certfile, self.args.ssl_keyfile)

        # write_to_terminal('run controller', color='green')
        # run
        uvicorn_main.run(
            host=self.args.__dict__['web.listen_address'],
            port=self.args.__dict__['web.listen_port'],
            telemetry_path='/metrics',
            ssl_keyfile=self.args.ssl_keyfile,
            ssl_certfile=self.args.ssl_certfile,
            ssl_keyfile_password=self.args.keyfile_password,
            ssl_ca_file=self.args.ssl_ca_file
        )


def main():
    args = parse_argv(sys.argv[1:])
    print(args)
    if is_exporter_alive(args.__dict__['web.listen_address'],
                         args.__dict__['web.listen_port']):
        write_to_terminal('Service has been started or the address already in use, exiting...', color='red')
    else:
        ExporterMain(args).run()

main()